
//
// Copyright 2009 Arne Halvorsen (arne.halvorsen@gmail.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Project page: http://code.google.com/p/webfg/

//
// 091201 - aha42 - Created.
//

package org.aha.webfg;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aha.mf4j.FlickrCalls;
import org.aha.mf4j.FlickrException;
import org.aha.mf4j.FlickrSession;
import org.aha.mf4j.flickrutil.People;
import org.aha.mf4j.response.FlickrObject;
import org.aha.mf4j.visitor.LookupVisitor;
import org.aha.mf4j.visitor.ToStringVisitor;
import org.aha.servlet.ParameterUtil;

/**
 * <p>
 *   Various utility methods of use when realizing gallery pages.
 * </p>
 * @author Arne Halvorsen (aha42)
 */
public final class WebfgUtil 
{
  private WebfgUtil(){} // Utility pattern dictates private constructor.
  
  /**
   * <p>
   *   Finds 
   *   {@link FlickrObject} with set data for special set titled
   *   {@code profile} among given sets.
   * </p>
   * @param sets Sets to search.
   * @return Found or {@code null} if none found.
   */
  public static FlickrObject findProfileSet(FlickrObject[] sets)
  {
    int n=sets.length;
    for (int i=0; i<n; i++)
    {
      FlickrObject curr=sets[i];
      String title=curr.getAttribute("title");
      if ("profile".equals(title)) return curr;
    }
    return null;
  }
  
  /**
   * <p>
   *   Finds 
   *   {@link FlickrObject} representing profile picture given id to profile
   *   set.
   * </p>
   * @param fc  {@link FlickrCalls} to use to query Flickr.
   * @param sid Set's id.
   * @return Found or {@code null} if none found.
   * @throws IOException If found.
   */
  public static FlickrObject findProfilePhoto(FlickrCalls fc, String sid) 
    throws IOException
  {
    if (fc==null)
    {
      throw new NullPointerException("fc");
    }
    if (sid==null)
    {
      throw new NullPointerException("sid");
    }
    
    FlickrObject[] photos=fc.getPhotosInSet(sid, null, null, null);
    int n=photos.length;
    for (int i=0; i<n; i++)
    {
      FlickrObject curr=photos[i];
      String title=curr.getAttribute("title");
      if ("portrait".equals(title)) return curr;
    }
    return null;
  }
  
  public static FlickrObject[] getProfilePhotos(FlickrCalls fc,
    FlickrSession fs, String sid, Map<String, String> attrs) 
    throws FlickrException
  {
    if (fc==null)
    {
      throw new NullPointerException("fc");
    }
    if (sid==null)
    {
      throw new NullPointerException("sid");
    }
    
    FlickrObject[] photos=fc.getPhotosInSet(sid, null, null, null);
    int n=photos.length;
    for (int i=0; i<n; i++)
    {
      FlickrObject curr=photos[i];
      TagUtil.getNameValueTags(fs, curr.getMandatoryAttribute("id"), attrs);
    }
    
    return photos;
  }
  
  private static final Random c_random=new Random();
  
  public static FlickrObject getRandomObject(FlickrObject[] fos)
  {
    if (fos==null)
    {
      throw new NullPointerException("fos");
    }
    
    int n=fos.length;
    switch (n)
    {
      case 0  : throw new IllegalArgumentException("fos.length==0");
      case 1  : return fos[0];
      default : return fos[c_random.nextInt(n)];
    }
  }
  
  /**
   * <p>
   *   Used for debug/info to print parsed Flickr query result to client as
   *   plain text.
   * </p>
   * @param forest Data to print.
   * @param resp   HTTP response.
   * @throws FlickrException If fails.
   */
  public static void showForest(FlickrObject[] forest, HttpServletResponse resp)
    throws IOException
  {
    ToStringVisitor tsv=new ToStringVisitor();
    FlickrObject.visit(forest, tsv);
    String s=tsv.toString();
  
    resp.setContentType("text/plain");
    PrintWriter pw=resp.getWriter();
    pw.print(s);
  }
  
  /**
   * <p>
   *   Gets 
   *   {@link FlickrObject} representing the collection being the basis for the
   *   gallery to generate.
   * </p>
   * @param fc   Utility to use to get collection/set tree from Flickr.
   * @param nsid User's id.
   * @param gid  Collection's id.
   * @return Found, {@code null} if non found.
   * @throws FlickrException If fails.
   */
  public static FlickrObject getCollection(FlickrCalls fc, String nsid, 
    String gid) throws FlickrException
  {
    if (fc==null)
    {
      throw new NullPointerException("fc");
    }
    if (nsid==null)
    {
      throw new NullPointerException("nsid");
    }
    
    FlickrObject retVal=null;
    FlickrObject[] forest=fc.getCollectionTrees(null, nsid);
    
    if (gid!=null)
    {
      LookupVisitor lv=new LookupVisitor().matchType("collection");
      retVal=lv.matchAttribute("title", gid).search(forest);
      if (retVal!=null) return retVal;
    }
    
    LookupVisitor lv=new LookupVisitor().matchType("collection");
    
    if (gid!=null) lv.matchAttribute("id", gid);
    else           lv.matchAttribute("title", "Gallery");
    
    return lv.search(forest);
  }
  
  /**
   * <p>
   *   Used for debug/info to print request parameters.
   * </p>
   * @param sb  Where to compile HTML.
   * @param req HTTP request.
   */
  @SuppressWarnings("unchecked")
  public static void printParameters(StringBuilder sb, HttpServletRequest req)
  {
    Enumeration names=req.getParameterNames();
    if (names.hasMoreElements())
    {
      sb.append("<code>");
      while (names.hasMoreElements())
      {
        String name=names.nextElement().toString();
        String val=req.getParameter(name);
        sb.append(name).append(" : ").append(val).append("<br/>");
      }
      sb.append("<code>");
    }
  }
  
  /**
   * <p>
   *   Gets 
   *   {@link FlickrObject} describing picture's size given size specification. 
   * </p>
   * @param sizes {@link FlickrObject}s to choose from.
   * @param size  Size specification.
   * @return Found or {@code null} if none found.
   * @throws IllegalArgumentException If {@code size} not 
   *         {@code 's' || 'm' || 'l'}.
   * @throws FlickrException If fails.
   */
  public static FlickrObject getSizeFo(FlickrObject[] sizes, String size)
    throws FlickrException
  {
    String val=null;
  
         if (size.equals("s")) val="Small";
    else if (size.equals("m")) val="Medium";
    else if (size.equals("l")) val="Large";
    else
    {
      throw new IllegalArgumentException("val not 's', 'm', 'l' but '"+size+
        "'");
    }
  
    int n=sizes.length;
    for (int i=0; i<n; i++)
    {
      FlickrObject curr=sizes[i]; 
      if (curr.getMandatoryAttribute("label").equals(val)) return curr;
    }
    return null;
  }
  
  /**
   * <p>
   *   Gets license HTML to place on gallery pages.
   * </p>
   * @param l License, may be {@code null} which means 
   *          {@code "All Rights Reserved"} 
   * @return HTML.
   */
  public static String getLicenseHtml(String l)
  {
    if (l==null)
    {
      return "<i>All Rights Reserved</i>";
    }
    
    return new StringBuilder("<i>").append(l).append("</i>").toString();
  }
  
  public static String getNsid(HttpServletRequest req, FlickrSession fs) 
    throws IOException
  {
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    String retVal=req.getParameter("nsid");
    if (retVal!=null) return retVal;
    
    String user=ParameterUtil.getMandatoryParameter("user", req);
    retVal=People.getNsidForUserName(user, fs);
    if (retVal==null) retVal=People.getNsidForEmail(user, fs);
    if (retVal==null)
    {
      throw new IOException("User : "+user+" not found");
    }
    return retVal;
  }
  
}
